import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.graph_objects as go
from datetime import datetime

# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

class StockAnalysis:
    def __init__(self, file_path):
        """初始化函数，读取Excel文件"""
        self.file_path = file_path
        self.data = None
        self.load_data()
        
    def load_data(self):
        """读取Excel数据并进行预处理"""
        print("正在读取数据...")
        self.data = pd.read_excel(self.file_path)
        
        # 确保日期列格式正确
        if '日期' in self.data.columns:
            self.data['日期'] = pd.to_datetime(self.data['日期'])
            self.data = self.data.sort_values('日期')
            self.data = self.data.set_index('日期')
        
        print(f"数据读取完成，共{self.data.shape[0]}行{self.data.shape[1]}列")
        
    def show_basic_info(self):
        """显示数据的基本信息和前5行"""
        print("\n数据前5行:")
        print(self.data.head())
        
        print("\n数据描述性统计:")
        # 选择数值型列进行描述性统计
        numeric_cols = self.data.select_dtypes(include=['float64', 'int64']).columns
        print(self.data[numeric_cols].describe())
        
    def calculate_correlation(self):
        """计算变量间的相关系数并绘制热力图"""
        # 选择数值型列计算相关系数
        numeric_cols = self.data.select_dtypes(include=['float64', 'int64']).columns
        corr_matrix = self.data[numeric_cols].corr()
        
        print("\n变量相关系数矩阵:")
        print(corr_matrix)
        
        # 绘制相关系数热力图
        plt.figure(figsize=(12, 10))
        sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', fmt='.2f', linewidths=0.5)
        plt.title('比亚迪股票数据变量相关系数热力图')
        plt.tight_layout()
        plt.savefig('相关系数热力图.png', dpi=300)
        plt.close()
        print("\n相关系数热力图已保存为'相关系数热力图.png'")
        
    def plot_2023_close_price(self):
        """绘制2023年全年的收盘价时序图"""
        # 筛选2023年的数据
        if '日期' not in self.data.index.names:
            # 如果日期不是索引，先将其设为索引
            self.data = self.data.set_index('日期')
            
        data_2023 = self.data[self.data.index.year == 2023]
        
        plt.figure(figsize=(14, 7))
        plt.plot(data_2023.index, data_2023['收盘'], 'b-', linewidth=2)
        plt.title('2023年比亚迪股票收盘价走势')
        plt.xlabel('日期')
        plt.ylabel('收盘价（元）')
        plt.grid(True, linestyle='--', alpha=0.7)
        plt.tight_layout()
        plt.savefig('2023年收盘价走势图.png', dpi=300)
        plt.close()
        print("2023年收盘价走势图已保存为'2023年收盘价走势图.png'")
        
    def plot_k_line(self):
        """绘制2023年4月到6月的K线图"""
        # 筛选2023年4月至6月的数据
        if '日期' not in self.data.index.names:
            self.data = self.data.set_index('日期')
            
        start_date = '2023-04-01'
        end_date = '2023-06-30'
        data_k = self.data[start_date:end_date]
        
        # 使用plotly绘制K线图
        fig = go.Figure(data=[go.Candlestick(
            x=data_k.index,
            open=data_k['开盘'],
            high=data_k['最高'],
            low=data_k['最低'],
            close=data_k['收盘'],
            name='K线'
        )])
        
        fig.update_layout(
            title='2023年4月至6月比亚迪股票K线图',
            xaxis_title='日期',
            yaxis_title='价格（元）',
            xaxis_rangeslider_visible=False,
            template='plotly_white'
        )
        
        # 保存为HTML文件以便交互查看
        fig.write_html('2023年4-6月K线图.html')
        print("2023年4-6月K线图已保存为'2023年4-6月K线图.html'")
        
        # 尝试使用matplotlib绘制K线图并保存为图片
        try:
            import matplotlib.dates as mdates
            from mplfinance.original_flavor import candlestick_ohlc
            
            # 创建新的matplotlib图形
            fig_mp, ax = plt.subplots(figsize=(14, 7))
            
            # 准备数据格式
            ohlc_data = []
            for date, row in data_k.iterrows():
                ohlc_data.append([mdates.date2num(date), row['开盘'], row['最高'], row['最低'], row['收盘']])
            
            # 绘制K线图
            candlestick_ohlc(ax, ohlc_data, width=0.6, colorup='red', colordown='green')
            
            # 设置格式
            ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
            fig_mp.autofmt_xdate()
            plt.title('2023年4月至6月比亚迪股票K线图')
            plt.xlabel('日期')
            plt.ylabel('价格（元）')
            plt.grid(True, linestyle='--', alpha=0.7)
            plt.tight_layout()
            
            # 保存图片
            plt.savefig('2023年4-6月K线图.png', dpi=300)
            plt.close()
            print("2023年4-6月K线图已保存为'2023年4-6月K线图.png'")
        except Exception as e:
            print(f"保存K线图图片时出错: {str(e)}")
            # 如果matplotlib方法失败，尝试重新使用kaleido
            try:
                fig.write_image('2023年4-6月K线图.png', scale=3)
                print("2023年4-6月K线图已保存为'2023年4-6月K线图.png'")
            except Exception as e2:
                print(f"使用kaleido保存图片也失败: {str(e2)}")
        
        # K线图分析
        self.analyze_k_line(data_k)
        
    def analyze_k_line(self, data_k):
        """分析K线图特征"""
        print("\n2023年4月至6月K线图分析:")
        
        # 计算基本统计量
        price_change = data_k['收盘'].pct_change()
        avg_daily_change = price_change.mean() * 100
        max_increase = price_change.max() * 100
        max_decrease = price_change.min() * 100
        
        # 计算波动率
        volatility = price_change.std() * 100
        
        # 计算上涨和下跌的天数
        up_days = (price_change > 0).sum()
        down_days = (price_change < 0).sum()
        
        print(f"平均日涨跌幅: {avg_daily_change:.2f}%")
        print(f"最大单日涨幅: {max_increase:.2f}%")
        print(f"最大单日跌幅: {max_decrease:.2f}%")
        print(f"日波动率: {volatility:.2f}%")
        print(f"上涨天数: {up_days}天")
        print(f"下跌天数: {down_days}天")
        
        # 检查是否有明显的趋势
        from scipy import stats
        x = np.arange(len(data_k))
        slope, intercept, r_value, p_value, std_err = stats.linregress(x, data_k['收盘'])
        
        trend = "上涨" if slope > 0 else "下跌" if slope < 0 else "横盘"
        print(f"整体趋势: {trend}")
        print(f"线性回归R²值: {r_value**2:.4f}")

# 主函数
def main():
    file_path = '比亚迪后复权历史行情数据.xlsx'
    
    # 创建分析对象
    analyzer = StockAnalysis(file_path)
    
    # 执行任务1：显示基本信息
    analyzer.show_basic_info()
    
    # 执行任务2：计算相关系数并绘制热力图
    analyzer.calculate_correlation()
    
    # 执行任务3：绘制2023年收盘价时序图
    analyzer.plot_2023_close_price()
    
    # 执行任务4：绘制K线图并分析
    analyzer.plot_k_line()
    
    print("\n所有分析任务已完成！")

if __name__ == '__main__':
    main()